Gatsby 實作 Layout 並使用 wrapPageElement、gatsby-plugin-layout 減少 Remount

2022-01-19 Wed

本文將提及以下內容

  • Gatsby 建立 Layout component 使用 children
  • 為何需要 Layout component
  • 建立資料夾結構
  • 建立 Layout component
  • 使用 Layout component
  • Unmount 問題
  • 解決元件卸載問題
    • 方法一 - 使用 gatsby-plugin-layout 插件
      • 安裝
      • 如何使用
    • 方法二 - gatsby-browser.js 中配置
  • 建立 component 帶入 children 參數
  • 引用 component 並加入內容傳遞給該 component

為何需要 Layout component

  • Gatsby 建立 Layout component 使用 children
    • 為何需要 Layout component

在建立網站時,選用 Gatsby 這樣的框架能夠提高開發效率。Gatsby 基於 React 技術,支持各種前端元件。隨著專案檔案增多,為了方便維持頁面的一致性和可維護性,我們可以建立一個 Layout component

Layout component 讓開發者能夠定義一個共用的界面框架,包括 Header、Navbar 和 Footer。這保證了使用者無論訪問網站的哪一部分,都能獲得一致的體驗。同時,使用 Layout 還能提升程式碼的重用率和專案的可維護性,減少了在每一個頁面重寫佈局程式碼的需求。

本文將深入探討在 Gatsby 專案中如何有效地運用 Layout component。我們將從基礎設置、定義 Layout 開始,再到如何在頁面裡實際應用,逐步展示利用 Layout 如何能夠提高網站的整體品質。

建立資料夾結構

首先先建立如下的資料夾結構

├─components
│      Footer.js
│      Layout.js
│      Navbar.js
│
├─images
│      icon.png
│
└─pages
        404.js
        about.js
        index.js
        test.js
  • components資料夾包含了重用的 UI 元件,如Layout.jsNavbar.jsFooter.js。這些元件可以在多個頁面間使用,以確保界面一致性和程式碼的高效重用。
  • images資料夾用於存放網站使用的圖片資源,如標誌和背景圖片等。
  • pages資料夾包含了網站的各個頁面,每個文件對應一個路徑。Gatsby 會自動將這些 JavaScript 文件轉換為網站的頁面。

建立 Layout component

Layout component 的主要作用是提供一個共用的框架,讓每個頁面都能嵌入其中,從而保持頁面的一致性和整潔性。在Layout.js中定義 Layout component 時,使用了 React 的{children}特性來插入子元件。這樣任何被<Layout></Layout>包裹的內容都會被當做子元件渲染在指定的位置。

import React from 'react';
import Navbar from './Navbar';
import Footer from './Footer';

const Layout = ({children}) => {
  return (
    <>
      <Navbar /> //先前有預先建立一個 Navbar component
      {children}
      <Footer /> //先前有預先建立一個 Navbar component
    </>
  );
};

export default Layout;

使用 Layout component

當 Layout component 準備好後,就可以在頁面中使用它了。例如在index.js中,你可以這樣使用 Layout 來包裹頁面內容:

import React from 'react';
import Layout from '../components/Layout';

const IndexPage = () => {
  return (
    <Layout>
      這是首頁的內容
    </Layout>
  );
};

export default IndexPage;

透過這種方式,index.js頁面的內容會被插入到 Layout 的{children}位置。這樣,無論新增多少頁面,只要用 Layout 包裹,就能自動繼承 Header 和 Footer 的共用佈局,大大節省了重復佈局的工作量。

Unmount 問題

Gatsby 預設並不會自動將頁面包裹在 Layout component 中。這意味著當從一個頁面切換到另一個頁面時,由於"Top level" Component 發生變化,React 會重新渲染所有子元件。這會導致像導航欄這樣的共用元件被卸載(unmount)和重新掛載(remount),從而破壞了 CSS 過渡效果或者這些元件內的 React 狀態。

解決元件卸載問題

為了防止在頁面變化時 Layout component 被卸載,我們可以專注於兩種主要的實現方式:使用gatsby-plugin-layout插件和直接在gatsby-browser.js文件中配置。 在 Gatsby 專案資料夾中避免 Layout component 在頁面切換時卸載,主要有兩種方法:使用gatsby-plugin-layout插件和在gatsby-browser.js中手動配置。

方法一 - 使用 gatsby-plugin-layout 插件

gatsby-plugin-layout插件自動實現wrapPageElement API,使得 Layout component 在頁面間切換時不會卸載。使用此插件可以簡化設置過程。

當使用gatsby-plugin-layout插件時,目的是讓 Layout component 在 Gatsby 專案資料夾的頁面間切換時不被卸載。這樣做有助於保持應用的狀態和避免重新加載共用元件。以下是如何安裝和配置這個插件的步驀:

安裝

首先,需要安裝插件到你的專案資料夾中:

npm install gatsby-plugin-layout

如何使用

安裝後,將這個插件加入到你的gatsby-config.js配置文件中。預設情況下,這個插件會尋找位於src/layouts/index.js的 Layout component

module.exports = {
  plugins: [`gatsby-plugin-layout`],
}

如果你的 Layout component 位於專案資料夾的其他位置,可以使用component選項指定其位置:

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-layout`,
      options: {
        component: require.resolve(`./relative/path/to/layout/component`),
      },
    },
  ],
}

加入此插件後則無需手動將頁面用 Layout component 包裹。插件會自動完成這一操作,讓你的每個頁面都被 Layout 所包裹,從而實現全站統一的佈局,並且在頁面之間切換時保持 Layout component 的持久化。

通過這種方式,提高了使用者體驗,因為共用元件,如導航欄,不會因為頁面切換而 remount。

方法二 - gatsby-browser.js 中配置

另一種方法是直接在gatsby-browser.js中使用wrapPageElement API 來保持 Layout component 的持久化。這提供了更多控制權。

在專案資料夾根目錄下建立gatsby-browser.js,並且加入以下程式碼:

const React = require("react");
const Layout = require("./src/components/Layout").default; // 確保路徑匹配

exports.wrapPageElement = ({ element, props }) => {
  return <Layout {...props}>{element}</Layout>;
};

如此一來就可以讓 Gatsby 在每個頁面外自動包裹 Layout component,實現全局佈局且在頁面切換時不重新掛載。

參考資料